package its_models.student_model.student_model_diagnosis;

import its_models.student_model.StudentModelProperties;
import data_structure.CircularStack;
import database_handler.DatabaseManager;
import help_util.DateTime;
import help_util.IndexConverter;
import model_controller.ControlLayer;
import sudoku_properties.SudokuGameInfoParam;

/*********************************************************************
 * Class StepsManagement
 * 1. Store all the steps of solving puzzle (exclude the calc data)
 *********************************************************************/

public class StepsManagement{

    /* construtors  */
    public StepsManagement(ControlLayer inputController){
        // 20091015 phrase2 start
        dbManager = new DatabaseManager(inputController);
        Controller = inputController;
        stepCount = 0;
        // 20091015 phrase2 end
        stepsStackSize = StudentModelProperties.getDefaultStepsStackSize();
        redoStepsStack = new CircularStack(stepsStackSize);
        undoStepsStack = new CircularStack(stepsStackSize);
        HintsUsed = new int[HINTS_LEVEL.length];
        for(int i=0; i<HINTS_LEVEL.length; i++){
            HintsUsed[i] = 0;
        }
        //stepsList = new ArrayList<String>();
    }
    public StepsManagement(int inputStepsStackSize,ControlLayer inputController ){
        // 20091015 phrase2 start
        dbManager = new DatabaseManager(inputController);
        Controller = inputController;
        stepCount = 0;
        // 20091015 phrase2 end
        stepsStackSize = inputStepsStackSize;
        redoStepsStack = new CircularStack(stepsStackSize);
        undoStepsStack = new CircularStack(stepsStackSize);
        HintsUsed = new int[HINTS_LEVEL.length];
        for(int i=0; i<HINTS_LEVEL.length; i++){
            HintsUsed[i] = 0;
        }
    }

    /* return successful or not to record steps */
    public void addSteps(int inputCellIndex, int inputInvolvedValue, String actionCommand){
        /* Format xx;yy-zz */
        String StepValue = inputCellIndex + CELL_INDEX_ACTION_SEPERATOR + actionCommand 
                + COMMAND_VARIABLE_SEPERATOR + inputInvolvedValue;
        /* Step 1 : add to undo steps stack */
        undoStepsStack.Push(StepValue);
        /* Step 2 : empty redo steps */
        redoStepsStack.emptyStack();
        /* Step 3 : put the steps progress into step list */
        // 20091016 phrase 2 start
        this.updateDBSteps(StepValue, actionCommand);
        // 20091016 phrase 2 end
    }
     

    /* return the undo steps */
    public String undoSteps(){
        String StepValue = undoStepsStack.Pop();
        redoStepsStack.Push(StepValue);
        // 20091016 phrase 2 start
        String actionCommand = Controller.getActionCommand(StepValue);
        /* for undo action, if we assign a value, undo helpsus to erase the value */
        if(actionCommand.equalsIgnoreCase(ASSIGN_VALUE_COMMAND)){
            actionCommand = ERASE_VALUE_COMMAND;
        }else if(actionCommand.equalsIgnoreCase(ERASE_VALUE_COMMAND)){
            actionCommand = ASSIGN_VALUE_COMMAND;
        }
        this.updateDBSteps(StepValue, actionCommand);
        // 20091016 phrase 2 end
        return StepValue;
    }

    /* return the redo Step */
    public String redoSteps(){
        String StepValue = redoStepsStack.Pop();
        undoStepsStack.Push(StepValue);
        // 20091016 phrase 2 start
        /* for redo action, if do what we store in stepValue*/
        String actionCommand = Controller.getActionCommand(StepValue);
        this.updateDBSteps(StepValue, actionCommand);
        // 20091016 phrase 2 end
        return StepValue;
    }

    // 20091016 phrase2 start
    /* return - void (only for steps record in stepsManagement )*/
    private void updateDBSteps(String stepValue, String actionCommand){
        final int cellIndex = Controller.getCellPosition(stepValue);
        final int involvedValue = Controller.getInvolvedValue(stepValue);
        int[] HintsUsedInCell = new int[HINTS_LEVEL.length];
        if(actionCommand.equalsIgnoreCase(ASSIGN_VALUE_COMMAND)){ /* Only done when user assign a value*/
            stepCount++;
            //String totalHintsUsed = "";
            for(int i=0; i<HINTS_LEVEL.length; i++){
                HintsUsedInCell[i] = Controller.getNumHintsUsed(i) - HintsUsed[i];
                HintsUsed[i] = Controller.getNumHintsUsed(i);
                //totalHintsUsed += Controller.getNumHintsUsed(i) + HINTS_SEPARATOR;
            }
            final int indexX = IndexConverter.getHorizontalIndex(cellIndex);
            final int indexY = IndexConverter.getVerticalIndex(cellIndex);
  
            int SGused = 0;
            int NSused = 0;
            int HSused = 0;
            String[] rules = Controller.getRuleUsed(indexX, indexY).split("\\|");
            for(int i=0; i<rules.length; i++){
                if(rules[i].trim().startsWith(LOGICAL_RULES[0])){
                    SGused = 1;
                }
                if(rules[i].trim().startsWith(LOGICAL_RULES[1])){
                    NSused = 1;
                }
                if(rules[i].trim().startsWith(LOGICAL_RULES[2])){
                    HSused = 1;
                }
            }
            
            /* if the steps is added successfully, stepsMatrix on that steps is added */
            if(!dbManager.addGameSolvingSteps(stepCount, cellIndex, involvedValue, 
                    HintsUsedInCell , SGused, NSused, HSused, Integer.toString(Controller.getTimeValueInSecond())
                    )){
              dbManager.recordError(this.getClass().getName().toString(), "Cannot add step ", DateTime.getTimestamp());
            }else{ // record the stepsMatrix
            }
        }
        else if(actionCommand.equalsIgnoreCase(ERASE_VALUE_COMMAND)){
            stepCount--;
            if(!dbManager.removeGameSolvingSteps(dbManager.getStepID(cellIndex))){
                dbManager.recordError(this.getClass().getName().toString(), "Cannot removed or update step ", DateTime.getTimestamp());
            }else{ // record the stepsMatrix
            }
        }
    }
    // 20091016 phrase end
    public boolean isUndoEnable(){
        boolean isEnabled = false;
        if (undoStepsStack.getNumOfElement() > 0){
            isEnabled = true;
        }
        return isEnabled;
    }

    public boolean isRedoEnable(){
        boolean isEnabled = false;
        if (redoStepsStack.getNumOfElement() > 0){
            isEnabled = true;
        }
        return isEnabled;
    }

    public int getInvlovedValue(String command){
        String[] InvolvedValueList = command.split(COMMAND_VARIABLE_SEPERATOR) ;
        /* -1 as the first 2 part is combined */
        final int involvedCellValue = Integer.parseInt(InvolvedValueList[INVOLVED_VALUE_PART -1]) ;
        return involvedCellValue;
    }

    public String getActionCommand(String command){
        String[] CellIndexList = command.split(CELL_INDEX_ACTION_SEPERATOR) ;
        String actionCommandNcellValue = CellIndexList[ACTION_COMMAND_PART] ;
        String[] actionCommandList = actionCommandNcellValue.split(COMMAND_VARIABLE_SEPERATOR) ;
        /* -1 is becos first part have extracted out */
        final String actionCommand = actionCommandList[ACTION_COMMAND_PART-1] ;
        return actionCommand;
    }

    public int getCellPosition(String command){
        String[] CellIndexList = command.split(CELL_INDEX_ACTION_SEPERATOR) ;
        final int cellIndex = Integer.parseInt(CellIndexList[INDEX_PART]) ;
        return cellIndex;
    }

    public void emptyUndoStack(){
         undoStepsStack = new CircularStack(stepsStackSize);
    }
    public void emptyRedoStack(){
        redoStepsStack = new CircularStack(stepsStackSize);
    }

    // 20091029 phrase2 start get correct steps count
    public int getCorrectStepsCount(){
        return stepCount;
    }
    // 20091029 phrase2 end

    /* local variables */
    /* store all steps of user */
    //private ArrayList<String> stepsList;
    /* manage redo undo action*/
    private CircularStack redoStepsStack;
    private CircularStack undoStepsStack;
    private int stepsStackSize;

    /* Srtack value commands & seperators */
    final String CELL_INDEX_ACTION_SEPERATOR = StudentModelProperties.getCellIndexActionSeperator();
    final String COMMAND_VARIABLE_SEPERATOR = StudentModelProperties.getCommandVariableSeperator();
    final String ERASE_VALUE_COMMAND = StudentModelProperties.getEraseValueCommand();
    final String ASSIGN_VALUE_COMMAND = StudentModelProperties.getAssignValueCommand();
    final String POSSIBLE_CALU_VALUE_COMMAND = StudentModelProperties.getPossibleCaluValueCommand();
    final String IMPOSSIBLE_CALU_VALUE_COMMAND = StudentModelProperties.getImpossibleCaluValueCommand();
    final int INDEX_PART = StudentModelProperties.getIndexPart();
    final int ACTION_COMMAND_PART = StudentModelProperties.getActionCommandPart();
    final int INVOLVED_VALUE_PART = StudentModelProperties.getInvoivedValuePart();

    // 20091015 phrase2 start
    /* Data Handler*/
    private DatabaseManager dbManager;
    private int stepCount;
    private ControlLayer Controller;
    
    
    /* Constant variables */
    final String[] HINTS_LEVEL = SudokuGameInfoParam.getHintsLevel();
    final String HINTS_SEPARATOR = SudokuGameInfoParam.getHintsSeparator();
    final String[] LOGICAL_RULES = SudokuGameInfoParam.getLogicalRules();

    // 20100113
    private int[] HintsUsed;

    // 20091015 phrase2 end
   
}

